﻿#include "network_interface.hpp"
#include <bitset>
#include <iostream>
#include <utility>
#include <vector>
#include <string>

#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>
#endif

#if defined (_WIN32)
// 将 PWCHAR 转换为 std::string
static auto wcharToString = [](PWCHAR wstr) -> std::string
{
    if (wstr == nullptr) return "";
    int size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
    std::string result(size, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &result[0], size, nullptr, nullptr);
    result.resize(size - 1); // 去除末尾的 null 字符
    return result;
};
#endif

std::vector<NetworkInterfaceInfo> NetworkInterface::getInterfaces(bool activeOnly)
{
    std::vector<NetworkInterfaceInfo> interfaces;

#ifdef _WIN32
    PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
    ULONG outBufLen = 0;
    DWORD dwRetVal = 0;

    // 获取适配器信息
    dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen);
    if (dwRetVal == ERROR_BUFFER_OVERFLOW)
    {
        pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(outBufLen);
        if (pAddresses == nullptr)
        {
            std::cerr << "Memory allocation failed" << std::endl;
            return interfaces;
        }

        dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen);
        if (dwRetVal != ERROR_SUCCESS)
        {
            std::cerr << "GetAdaptersAddresses failed with error: " << dwRetVal << std::endl;
            free(pAddresses);
            return interfaces;
        }
    }

    // 遍历适配器
    PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses;
    while (pCurrAddresses)
    {
        NetworkInterfaceInfo info;

        info.name = wcharToString(pCurrAddresses->FriendlyName);
        info.description = wcharToString(pCurrAddresses->Description);
        info.isUp = (pCurrAddresses->OperStatus == IfOperStatusUp);

        // 获取 MAC 地址
        if (pCurrAddresses->PhysicalAddressLength > 0)
        {
            char mac[18];
            sprintf_s(mac, "%02X:%02X:%02X:%02X:%02X:%02X",
                      pCurrAddresses->PhysicalAddress[0], pCurrAddresses->PhysicalAddress[1],
                      pCurrAddresses->PhysicalAddress[2], pCurrAddresses->PhysicalAddress[3],
                      pCurrAddresses->PhysicalAddress[4], pCurrAddresses->PhysicalAddress[5]);
            info.macAddress = mac;
        }

        // 获取 IP 地址、子网掩码和网关
        PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pCurrAddresses->FirstUnicastAddress;
        while (pUnicast)
        {
            char ip[INET6_ADDRSTRLEN];
            char subnet[INET6_ADDRSTRLEN];

            std::pair<std::string, std::string> pair;
            // IP 地址
            if (pUnicast->Address.lpSockaddr->sa_family == AF_INET)
            {
                auto* sa_in = reinterpret_cast<struct sockaddr_in*>(pUnicast->Address.lpSockaddr);
                inet_ntop(AF_INET, &(sa_in->sin_addr), ip, INET6_ADDRSTRLEN);
                pair.first = ip;
                // info.ipAddresses.emplace_back(ip);
            }

            // 子网掩码
            if (pUnicast->Address.lpSockaddr->sa_family == AF_INET)
            {
                in_addr subnetMask{};
                subnetMask.s_addr = htonl(0xFFFFFFFF << (32 - pUnicast->OnLinkPrefixLength));
                inet_ntop(AF_INET, &subnetMask, subnet, INET6_ADDRSTRLEN);
                pair.second = subnet;
                // info.subnetMasks.emplace_back(subnet);
            }
            info.Addresses.push_back(pair);
            pUnicast = pUnicast->Next;
        }

        // 获取 MTU
        info.mtu = pCurrAddresses->Mtu;

        interfaces.push_back(info);
        pCurrAddresses = pCurrAddresses->Next;
    }

    free(pAddresses);
#else
    struct ifaddrs *ifaddr, *ifa;
    if (getifaddrs(&ifaddr) == -1)
    {
        std::cerr << "getifaddrs failed" << std::endl;
        return interfaces;
    }

    for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
    {
        if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_INET)
            continue;

        NetworkInterfaceInfo info;
        info.name = ifa->ifa_name;
        info.isUp = (ifa->ifa_flags & IFF_UP) != 0;

        // 获取 IP 地址和子网掩码
        char ip[INET_ADDRSTRLEN];
        char subnet[INET_ADDRSTRLEN];
        struct sockaddr_in* sa_in = (struct sockaddr_in*)ifa->ifa_addr;
        struct sockaddr_in* sa_netmask = (struct sockaddr_in*)ifa->ifa_netmask;
        
        std::pair<std::string, std::string> pair;
        if (inet_ntop(AF_INET, &(sa_in->sin_addr), ip, INET_ADDRSTRLEN) != nullptr)
        {
            pair.first = ip;
            // info.ipAddresses.push_back(ip);
        }

        inet_ntop(AF_INET, &(sa_netmask->sin_addr), subnet, INET_ADDRSTRLEN);
        pair.second = subnet;
        info.Addresses.push_back(pair);
        // info.subnetMasks.push_back(subnet);

        interfaces.push_back(info);
    }

    freeifaddrs(ifaddr);
#endif

    return interfaces;
}

std::vector<NetworkInterfaceInfo> NetworkInterface::getAllInterfaces()
{
    return getInterfaces(false);
}

std::vector<NetworkInterfaceInfo> NetworkInterface::getActiveInterfaces()
{
    return getInterfaces(true);
}

cpp::Result<> NetworkInterface::setInterfaceConfig(const std::string& interfaceName, const std::string& ipAddress, const std::string& subnetMask)
{
#ifdef _WIN32
    return cpp::Result<>::Err("No support platform.");
#else
    try {
        // 计算 CIDR
        auto subnetToCidr = [](const std::string& subnet) -> int {
            try {
                size_t pos = 0;
                int count = 0;
                std::string token;
                std::string s = subnet;
                while ((pos = s.find('.')) != std::string::npos) {
                    token = s.substr(0, pos);
                    count += std::bitset<8>(std::stoi(token)).count();
                    s.erase(0, pos + 1);
                }
                count += std::bitset<8>(std::stoi(s)).count();
                return count;
            } catch (...) {
                return 24; // 默认返回 24 (/24 = 255.255.255.0)
            }
        };

        int cidr = subnetToCidr(subnetMask);

        // 构造 netplan 命令
        std::string ipCmd = "netplan set ethernets." + interfaceName + ".addresses=[" + ipAddress + "/" + std::to_string(cidr) + "]";
        std::string applyCmd = "netplan apply";

        // 执行命令
        auto executeCommand = [](const std::string& cmd) -> bool {
            FILE* pipe = popen(cmd.c_str(), "r");
            if (!pipe) return false;
            pclose(pipe);
            return true;
        };

        if (!executeCommand(ipCmd)) {
            // std::cerr << "Failed to set IP address." << std::endl;
            return cpp::Result<>::Err("Failed to set IP address.");
        }

        if (!executeCommand(applyCmd)) {
            // std::cerr << "Failed to apply netplan configuration." << std::endl;
            return cpp::Result<>::Err("Failed to apply netplan configuration.");
        }

        return cpp::Result<>::Ok();
    } catch (const std::exception& e) {
        return cpp::Result<>::Err(e.what());
    }
#endif
}

